home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / I8250.C < prev    next >
C/C++ Source or Header  |  1997-05-24  |  21KB  |  934 lines

  1. #ifdef MSDOS
  2. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC
  3.  * Copyright 1991 Phil Karn, KA9Q
  4.  *
  5.  * 16550A support plus some statistics added mah@hpuviea.at 15/7/89
  6.  *
  7.  * CTS hardware flow control from dkstevens@ucdavis,
  8.  * additional stats from delaroca@oac.ucla.edu added by karn 4/17/90
  9.  * Feb '91      RLSD line control reorganized by Bill_Simpson@um.cc.umich.edu
  10.  * Sep '91      All control signals reorganized by Bill Simpson
  11.  * Jan '92      Added force 16550 fifo command
  12.  *
  13.  * Mods by PA0GRI
  14.  */
  15. #include "global.h"
  16. #include <dos.h>
  17. #include "mbuf.h"
  18. #include "proc.h"
  19. #include "iface.h"
  20. #include "i8250.h"
  21. #include "asy.h"
  22. #include "devparam.h"
  23. #include "pc.h"
  24. #include "kisspoll.h"
  25. #include "timer.h"
  26. #include "commands.h"
  27.  
  28. #if !defined(_lint)
  29. static char rcsid[] OPTIONAL = "$Id: i8250.c,v 1.15 1997/05/24 13:07:08 root Exp root $";
  30. #endif
  31.  
  32. #ifdef TIPMAIL
  33. extern struct suspended {
  34.     struct iface *ifp;
  35.     unsigned timeout;
  36.     char modem;
  37. } Tipsuspended[ASY_MAX];
  38. #include "cmdparse.h"
  39. extern struct cmds Cmds[];
  40. #endif
  41.  
  42. static void asy_monitor (int dev,void *p1,void *p2);
  43.  
  44. static void asy_output (int dev,char *buf,unsigned short cnt);
  45. static int asyrxint (struct asy *asyp);
  46. static void asytxint (int dev);
  47. static void asymsint (int dev);
  48.  
  49. static void asy_tx (int dev,void *p1,void *p2);
  50.  
  51. struct asy Asy[ASY_MAX];
  52.  
  53. /* ASY interrupt handlers */
  54. static void (*Handle[])() = {asy0vec,asy1vec,asy2vec,asy3vec,asy4vec};
  55. static unsigned char fifo_setup;
  56.  
  57.  
  58. /* Initialize asynch port "dev" */
  59. int
  60. asy_init(dev,ifp,arg1,arg2,bufsize,trigchar,monitor,speed,force,triglevel,polled)
  61. int dev;
  62. struct iface *ifp;
  63. char *arg1,*arg2;    /* Attach args for address and vector */
  64. int16 bufsize;
  65. int trigchar;
  66. char monitor;
  67. long speed;
  68. int force;
  69. int triglevel;
  70. int polled;
  71. {
  72.     register unsigned base;
  73.     register struct fifo *fp;
  74.     register struct asy *ap;
  75.     char *ifn;
  76.     char i_state;
  77.     long interval;
  78.  
  79.     ap = &Asy[dev];
  80.     ap->iface = ifp;
  81.     ap->addr = htoi(arg1);
  82.     ap->vec = htoi(arg2);
  83.  
  84. #ifdef POLLEDKISS
  85.     ap->poller = NULL;
  86. #endif
  87.  
  88.     /* Set up receiver FIFO */
  89.     fp = &ap->fifo;
  90.     fp->buf = mallocw(bufsize);
  91.     fp->bufsize = bufsize;
  92.     fp->wp = fp->rp = fp->buf;
  93.     fp->cnt = 0;
  94.     fp->hiwat = 0;
  95.     fp->overrun = 0;
  96.     base = ap->addr;
  97.     ap->trigchar = trigchar;
  98.  
  99.     /* Purge the receive data buffer */
  100.     (void)inportb(base+RBR);
  101.  
  102.     i_state = disable ();
  103.  
  104.     /* Save original interrupt vector, mask state, control bits */
  105.     ap->save.vec = getirq(ap->vec);
  106.     ap->save.mask = getmask(ap->vec);
  107.     ap->save.lcr = inportb(base+LCR);
  108.     ap->save.ier = inportb(base+IER);
  109.     ap->save.mcr = inportb(base+MCR);
  110.     ap->save.msr = inportb(base+MSR);
  111.     ap->save.iir = inportb(base+IIR);
  112.  
  113.     /* save speed bytes */
  114.     setbit(base+LCR,LCR_DLAB);
  115.     ap->save.divl = inportb(base+DLL);
  116.     ap->save.divh = inportb(base+DLM);
  117.     clrbit(base+LCR,LCR_DLAB);
  118.  
  119.     /* save some information on the starting state */
  120.     ap->cts_flow_control = (ap->save.msr & MSR_CTS) ? FOUND_UP : FOUND_DOWN;
  121.     ap->rlsd_line_control = (ap->save.msr & MSR_RLSD) ? FOUND_UP : FOUND_DOWN;
  122.     ap->dtr_usage = (ap->save.mcr & MCR_DTR) ? FOUND_UP : FOUND_DOWN;
  123.     ap->rts_usage = (ap->save.mcr & MCR_RTS) ? FOUND_UP : FOUND_DOWN;
  124.  
  125.     /* Set interrupt vector to SIO handler */
  126.     setirq(ap->vec,Handle[dev]);
  127.  
  128.     /* Set line control register: 8 bits, no parity */
  129.     outportb(base+LCR,(char)LCR_8BITS);
  130.  
  131.     /* determine if 16550A, turn on FIFO mode and clear RX and TX FIFOs */
  132.     outportb(base+FCR,(char) FIFO_ENABLE);
  133.  
  134.     /* According to National ap note AN-493, the FIFO in the 16550 chip
  135.      * is broken and must not be used. To determine if this is a 16550A
  136.      * (which has a good FIFO implementation) check that both bits 7
  137.      * and 6 of the IIR are 1 after setting the fifo enable bit. If
  138.      * not, don't try to use the FIFO.
  139.      */
  140.     /* Set the fifo trigger level according to the user's wishes :-) - WG7J */
  141.     if(triglevel == 1)
  142.         fifo_setup = FIFO_SETUP1;
  143.     else if(triglevel == 4)
  144.         fifo_setup = FIFO_SETUP4;
  145.     else if(triglevel == 8)
  146.         fifo_setup = FIFO_SETUP8;
  147.     else if(triglevel == 14)
  148.         fifo_setup = FIFO_SETUP14;
  149.     else
  150.         fifo_setup = FIFO_SETUP4;    /* default to 4 */
  151.  
  152.     if (((inportb(base+IIR) & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED) || force) {
  153.         ap->is_16550a = TRUE;
  154.         outportb(base+FCR,fifo_setup);
  155.     } else {
  156.         /* Chip is not a 16550A. In case it's a 16550 (which
  157.          * has a broken FIFO), turn off the FIFO bit.
  158.          */
  159.         outportb(base+FCR,(char)0);
  160.         ap->is_16550a = FALSE;
  161.     }
  162.  
  163.     /* Turn on modem status and receive interrupts,
  164.      * leave transmit interrupts off for now.
  165.      */
  166.     outportb(base+IER, (char)(IER_MS + IER_DAV));
  167.  
  168.     /* Turn on 8250 master interrupt enable (connected to OUT2) */
  169.     setbit(base+MCR,(MCR_OUT2));
  170.  
  171.     /* Enable interrupt */
  172.     maskon(ap->vec);
  173.     restore(i_state);
  174.  
  175.     asy_speed(dev,speed);
  176.  
  177.     if ( monitor ) {
  178.         /* set up to monitor line signals */
  179.         ap->monitor = newproc( ifn = if_name( ifp, " monitor" ),
  180.                 256, asy_monitor, ifp->dev, ifp, NULL, 0);
  181.         free(ifn);
  182.         kwait(NULL);    /* let hooks get set up */
  183.     }
  184.  
  185.     ifp->txproc = newproc( ifn = if_name(ifp," tx"),
  186.             256, asy_tx, dev, ifp, NULL, 0);
  187.     free(ifn);
  188.  
  189.     if ( (ap->dtr_usage & FOUND_UP)
  190.       && (ap->rlsd_line_control & FOUND_UP)
  191.      || ap->monitor == NULL ) {
  192.         if ( ifp->iostatus != NULL ) {
  193.             (*ifp->iostatus)(ifp, PARAM_UP, 0L);
  194.         }
  195.     }
  196.  
  197. #ifdef POLLEDKISS
  198.     if (polled) {
  199.         /* Calculate the poll interval: some processing time +
  200.          * the packet duration for a mtu size packet.
  201.          */
  202.         interval = (((long)ifp->mtu * 10000L) / speed);
  203.         ap->poller = newproc (ifn=if_name(ifp," poller"),
  204.             384,kiss_poller,ifp->xdev,(void *)interval,NULL,0);
  205.         free (ifn);
  206.     }
  207. #endif
  208.     return 0;
  209. }
  210.  
  211.  
  212. int
  213. asy_stop(ifp)
  214. struct iface *ifp;
  215. {
  216.     register unsigned base;
  217.     register struct asy *ap;
  218.     char i_state;
  219.  
  220.     ap = &Asy[ifp->dev];
  221.  
  222. #ifdef POLLEDKISS
  223.     if (ap->poller)
  224.         killproc (ap->poller);
  225. #endif
  226.      if ( ap->monitor != NULL ) {
  227.         ap->rlsd_line_control = IGNORED;
  228.         killproc( ap->monitor );
  229.         ap->monitor = NULL;
  230.     }
  231.     ap->iface = NULLIF;
  232.  
  233.     base = ap->addr;
  234.  
  235.     /* Purge the receive data buffer */
  236.     (void)inportb(base+RBR);
  237.  
  238.     /* and hardware fifos if available */
  239.     if (ap->is_16550a) {
  240.         if((ap->save.iir & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED)
  241.             outportb(base+FCR,fifo_setup);
  242.         else
  243.             outportb(base+FCR,0);
  244.     }
  245.  
  246.     /* Restore original interrupt vector and 8259 mask state */
  247.     i_state = disable ();
  248.     setirq(ap->vec,ap->save.vec);
  249.     if(ap->save.mask)
  250.         maskon(ap->vec);
  251.     else
  252.         maskoff(ap->vec);
  253.  
  254.     /* Restore speed regs */
  255.     setbit(base+LCR,LCR_DLAB);
  256.     outportb(base+DLL,ap->save.divl);    /* Low byte */
  257.     outportb(base+DLM,ap->save.divh);    /* Hi byte */
  258.     clrbit(base+LCR,LCR_DLAB);
  259.  
  260.     /* Restore control regs */
  261.     /* except, leave DTR in current state {bsimpson} */
  262.     outportb(base+LCR,ap->save.lcr);
  263.     outportb(base+IER,ap->save.ier);
  264.     outportb(base+MCR,ap->save.mcr);
  265. #ifdef notdef
  266.     outportb(base+MCR,(ap->save.mcr &~ MCR_DTR)
  267.             | (inportb(base+MCR) & MCR_DTR) );
  268. #endif
  269.  
  270.     restore(i_state);
  271.     free(ap->fifo.buf);
  272.     return 0;
  273. }
  274.  
  275.  
  276. /* Set asynch line speed */
  277. int
  278. asy_speed(dev,bps)
  279. int dev;
  280. long bps;
  281. {
  282.     register unsigned base;
  283.     register long divisor;
  284.     struct asy *asyp;
  285.     char i_state;
  286.  
  287.     if(bps <= 0 || dev >= ASY_MAX)
  288.         return -1;
  289.     asyp = &Asy[dev];
  290.     if(asyp->iface == NULLIF)
  291.         return -1;
  292.  
  293.     switch(bps) {
  294.     case 300:
  295.     case 1200:
  296.     case 2400:
  297.     case 4800:
  298.     case 9600:
  299.     case 19200:
  300.     case 38400L:
  301.     case 56700L:
  302.     case 115200L:
  303.         /* supported speed */
  304.         asyp->speed = bps;
  305.         break;
  306.     default:
  307.         /* unsupported speed */
  308.         return -1;
  309.     };
  310.  
  311.     base = asyp->addr;
  312.     divisor = BAUDCLK / bps;
  313.  
  314.     i_state = disable ();
  315.  
  316.     /* Purge the receive data buffer */
  317.     (void)inportb(base+RBR);
  318.     if (asyp->is_16550a)        /* clear tx+rx fifos */
  319.         outportb(base+FCR,fifo_setup);
  320.  
  321.     /* Turn on divisor latch access bit */
  322.     setbit(base+LCR,LCR_DLAB);
  323.  
  324.     /* Load the two bytes of the register */
  325.     outportb(base+DLL,(char)(divisor & 0xff));        /* Low byte */
  326.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));    /* Hi byte */
  327.  
  328.     /* Turn off divisor latch access bit */
  329.     clrbit(base+LCR,LCR_DLAB);
  330.  
  331.     restore(i_state);
  332.     return 0;
  333. }
  334.  
  335.  
  336. /* Asynchronous line I/O control */
  337. int32
  338. asy_ioctl(ifp,cmd,set,val)
  339. struct iface *ifp;
  340. int cmd;
  341. int set;
  342. int32 val;
  343. {
  344.     struct asy *ap = &Asy[ifp->dev];
  345.     int16 base = ap->addr;
  346.  
  347.     switch(cmd){
  348.     case PARAM_SPEED:
  349.         if(set)
  350.             asy_speed(ifp->dev,val);
  351.         return ap->speed;
  352.     case PARAM_DTR:
  353.         if(set) {
  354.             writebit(base+MCR,MCR_DTR,(int)val);
  355.             ap->dtr_usage = (val) ? MOVED_UP : MOVED_DOWN;
  356.         }
  357.         return (inportb(base+MCR) & MCR_DTR) ? TRUE : FALSE;
  358.     case PARAM_RTS:
  359.         if(set) {
  360.             writebit(base+MCR,MCR_RTS,(int)val);
  361.             ap->rts_usage = (val) ? MOVED_UP : MOVED_DOWN;
  362.         }
  363.         return (inportb(base+MCR) & MCR_RTS) ? TRUE : FALSE;
  364.     case PARAM_DOWN:
  365.         clrbit(base+IER,(char)IER_DAV);
  366.         clrbit(base+MCR,MCR_RTS);
  367.         clrbit(base+MCR,MCR_DTR);
  368.         ap->rts_usage = MOVED_DOWN;
  369.         ap->dtr_usage = MOVED_DOWN;
  370.         return FALSE;
  371.     case PARAM_UP:
  372.         setbit(base+IER,(char)IER_DAV);
  373.         setbit(base+MCR,MCR_RTS);
  374.         setbit(base+MCR,MCR_DTR);
  375.         ap->rts_usage = MOVED_UP;
  376.         ap->dtr_usage = MOVED_UP;
  377.         return TRUE;
  378.     case PARAM_BLIND:
  379.         setbit(base+IER,(char)IER_DAV);
  380.         ap->rlsd_line_control = IGNORED;
  381.  
  382.         if ( ap->monitor != NULL ) {
  383.             killproc( ap->monitor );
  384.             ap->monitor = NULL;
  385.         }
  386.  
  387.         /* can't see what we are doing, so pretend we're up */
  388.         if ( ifp->iostatus != NULL ) {
  389.             (*ifp->iostatus)(ifp, PARAM_UP, 0L);
  390.         }
  391.         return TRUE;
  392.     };
  393.     return -1;
  394. }
  395.  
  396.  
  397. /* Start transmission of a buffer on the serial transmitter */
  398. static void
  399. asy_output(dev,buf,cnt)
  400. int dev;
  401. char *buf;
  402. unsigned short cnt;
  403. {
  404.     register struct dma *dp;
  405.     unsigned base;
  406.     char i_state;
  407.     char ier;
  408.     struct asy *asyp;
  409.  
  410.     if(dev < 0 || dev >= ASY_MAX)
  411.         return;
  412.     asyp = &Asy[dev];
  413.     if(asyp->iface == NULLIF)
  414.         return;
  415.  
  416.     base = asyp->addr;
  417.     dp = &asyp->dma;
  418.     i_state = disable ();
  419.  
  420.     if(dp->flags){
  421.         restore(i_state);
  422.         return;    /* Already busy */
  423.     }
  424.     dp->data = buf;
  425.     dp->cnt = cnt;
  426.     dp->flags = 1;
  427.  
  428.     if(asyp->cts_flow_control & MOVED_DOWN){
  429.         /* CTS flow control is enabled; let the modem control
  430.          * interrupt enable transmit interrupts if CTS is off
  431.          */
  432.         ier = IER_MS;
  433.         if(inportb(base+MSR) & MSR_CTS)
  434.             ier |= IER_TxE;
  435.     } else {
  436.         /* Enable transmit interrupts; this will cause an immediate
  437.          * interrupt that will start things going
  438.          */
  439.         ier = IER_TxE;
  440.     }
  441.     setbit(base+IER,ier);
  442.  
  443.     /* "Kick start" the transmitter interrupt routine, in case just
  444.      * setting the interrupt enable bit doesn't cause an interrupt
  445.      */
  446.     if(ier & IER_TxE)
  447.         asytxint(dev);
  448.     restore(i_state);
  449. }
  450.  
  451.  
  452. /* Blocking read from asynch line
  453.  * Returns character or -1 if aborting
  454.  * Returns -2 (CD_DOWN) if carrier checking is on and dropped
  455.  */
  456. int
  457. get_asy(dev)
  458. int dev;
  459. {
  460.     char i_state;
  461.     register struct fifo *fp;
  462.     char c;
  463.  
  464.     fp = &Asy[dev].fifo;
  465.  
  466.     i_state = disable ();
  467.     while(fp->cnt == 0){
  468.         if(kwait(fp) != 0){
  469.             restore(i_state);
  470.             return -1;
  471.         }
  472.     }
  473.     fp->cnt--;
  474.     restore(i_state);
  475.  
  476.     c = *fp->rp++;
  477.     if(fp->rp >= &fp->buf[fp->bufsize])
  478.         fp->rp = fp->buf;
  479.  
  480.     return uchar(c);
  481. }
  482.  
  483.  
  484. /* Interrupt handler for 8250 asynch chip (called from asyvec.asm) */
  485. void
  486. asyint(dev)
  487. int dev;
  488. {
  489.     struct asy *asyp;
  490.     unsigned base;
  491.     char iir;
  492.  
  493.     asyp = &Asy[dev];
  494.     base = asyp->addr;
  495.     while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
  496.         switch(iir & IIR_ID_MASK){
  497.         case IIR_RDA:    /* Receiver interrupt */
  498.             asyrxint(asyp);
  499.             break;
  500.         case IIR_THRE:    /* Transmit interrupt */
  501.             asytxint(dev);
  502.             break;
  503.         case IIR_MSTAT:    /* Modem status change */
  504.             asymsint(dev);
  505.             asyp->msint_count++;
  506.             break;
  507.         }
  508.         /* should happen at end of a single packet */
  509.         if(iir & IIR_FIFO_TIMEOUT)
  510.             asyp->fifotimeouts++;
  511.     }
  512. }
  513.  
  514.  
  515. /* Process 8250 receiver interrupts */
  516. static int
  517. asyrxint(asyp)
  518. struct asy *asyp;
  519. {
  520.     register struct fifo *fp;
  521.     unsigned base;
  522.     char c,lsr;
  523.     int cnt = 0;
  524.     int trigseen = FALSE;
  525.  
  526.     asyp->rxints++;
  527.     base = asyp->addr;
  528.     fp = &asyp->fifo;
  529.     for(;;){
  530.         lsr = inportb(base+LSR);
  531.         if(lsr & LSR_OE)
  532.             asyp->overrun++;
  533.  
  534.         if(lsr & LSR_DR){
  535.             asyp->rxchar++;
  536.             c = inportb(base+RBR);
  537.             if(asyp->trigchar == uchar(c))
  538.                 trigseen = TRUE;
  539.             /* If buffer is full, we have no choice but
  540.              * to drop the character
  541.              */
  542.             if(fp->cnt != fp->bufsize){
  543.                 *fp->wp++ = c;
  544.                 if(fp->wp >= &fp->buf[fp->bufsize])
  545.                     /* Wrap around */
  546.                     fp->wp = fp->buf;
  547.                 fp->cnt++;
  548.                 if(fp->cnt > fp->hiwat)
  549.                     fp->hiwat = fp->cnt;
  550.                 cnt++;
  551.             } else
  552.                 fp->overrun++;
  553.         } else
  554.             break;
  555.     }
  556.     if(cnt > asyp->rxhiwat)
  557.         asyp->rxhiwat = cnt;
  558.     if(trigseen)
  559.         ksignal(fp,1);
  560.     return cnt;
  561. }
  562.  
  563.  
  564. /* Handle 8250 transmitter interrupts */
  565. static void
  566. asytxint(dev)
  567. int dev;
  568. {
  569.     register struct dma *dp;
  570.     register unsigned base;
  571.     register int count;
  572.     struct asy *asyp;
  573.  
  574.     asyp = &Asy[dev];
  575.     base = asyp->addr;
  576.     dp = &asyp->dma;
  577.     asyp->txints++;
  578.     if(!dp->flags){
  579.         /* "Shouldn't happen", but disable transmit
  580.          * interrupts anyway
  581.          */
  582.         clrbit(base+IER,IER_TxE);
  583.         return;    /* Nothing to send */
  584.     }
  585.     if(!(inportb(base+LSR) & LSR_THRE))
  586.         return;    /* Not really ready */
  587.  
  588.     /* If it's a 16550A, load up to 16 chars into the tx hw fifo
  589.      * at once. With an 8250, it can be one char at most.
  590.      */
  591.     if(asyp->is_16550a){
  592.         count = min(dp->cnt,OUTPUT_FIFO_SIZE);
  593.  
  594.         /* 16550A: LSR_THRE will drop after the first char loaded
  595.          * so we can't look at this bit to determine if the hw fifo is
  596.          * full. There seems to be no way to determine if the tx fifo
  597.          * is full (any clues?). So we should never get here while the
  598.          * fifo isn't empty yet.
  599.          */
  600.         asyp->txchar += count;
  601.         dp->cnt -= count;
  602. #ifdef    notdef    /* This is apparently too fast for some chips */
  603.         dp->data = outbuf(base+THR,dp->data,count);
  604. #else
  605.         while(count-- != 0)
  606.             outportb(base+THR,*dp->data++);
  607. #endif
  608.         if(dp->cnt == 0){
  609.             dp->flags = 0;
  610.             /* Disable transmit interrupts */
  611.             clrbit(base+IER,IER_TxE);
  612.             ksignal(asyp,1);
  613.         }
  614.     } else {    /* 8250 */
  615.         do {
  616.             asyp->txchar++;
  617. #if defined(HP95)
  618.             /* bug work-around, by Ron WA7TAS */
  619.             clrbit(base+IER,IER_TxE);
  620.             outportb(base+THR,*dp->data++);
  621.             setbit(base+IER,IER_TxE);
  622. #else
  623.             outportb(base+THR,*dp->data++);
  624. #endif
  625.             if(--dp->cnt == 0){
  626.                 dp->flags = 0;
  627.                 /* Disable transmit interrupts */
  628.                 clrbit(base+IER,IER_TxE);
  629.                 ksignal(asyp,1);
  630.                 break;
  631.             }
  632.         } while(inportb(base+LSR) & LSR_THRE);
  633.     }
  634. }
  635.  
  636.  
  637. /* Handle 8250 modem status change
  638.  *    If the signals are unchanging, we ignore them.
  639.  *    If they change, we use them to condition the line.
  640.  */
  641. static void
  642. asymsint(dev)
  643. int dev;
  644. {
  645.     struct asy *ap = &Asy[dev];
  646.     unsigned base = ap->addr;
  647.  
  648.     ap->msr = inportb(base+MSR);
  649.  
  650.     if ( ap->msr & MSR_CTS ) {
  651.         switch ( ap->cts_flow_control ) {
  652.         case FOUND_DOWN:
  653.         case MOVED_DOWN:
  654.             ap->cts_flow_control = MOVED_UP;
  655.  
  656.             /* CTS now asserted, enable Transmit interrupts */
  657.             if(ap->dma.flags)
  658.                 setbit(base+IER,IER_TxE);
  659.             break;
  660.         };
  661.     } else {
  662.         switch ( ap->cts_flow_control ) {
  663.         case FOUND_UP:
  664.         case MOVED_UP:
  665.             ap->cts_flow_control = MOVED_DOWN;
  666.  
  667.             /* CTS now dropped, disable Transmit interrupts */
  668.             clrbit(base+IER,IER_TxE);
  669.             break;
  670.         };
  671.     }
  672.  
  673.     if ( ap->msr & MSR_RLSD ) {
  674.         switch ( ap->rlsd_line_control ) {
  675.         case FOUND_DOWN:
  676.         case MOVED_DOWN:
  677.             ap->rlsd_line_control = MOVED_UP;
  678.  
  679.             /* RLSD just went up */
  680.             ksignal( &(ap->rlsd_line_control), 1 );
  681.             break;
  682.         };
  683.     } else {
  684.         switch ( ap->rlsd_line_control ) {
  685.         case FOUND_UP:
  686.         case MOVED_UP:
  687.             ap->rlsd_line_control = MOVED_DOWN;
  688.  
  689.             /* RLSD just went down */
  690.             ksignal( &(ap->rlsd_line_control), 1 );
  691.             break;
  692.         };
  693.     }
  694.  
  695.     if ( ap->msr & (MSR_TERI | MSR_RI) ) {
  696.         asy_ioctl( ap->iface, PARAM_UP, TRUE, 0L );
  697.     }
  698. }
  699.  
  700.  
  701. /* Wait for a signal that the RLSD modem status has changed */
  702. int
  703. get_rlsd_asy(dev, new_rlsd)
  704. int dev;
  705. int new_rlsd;
  706. {
  707.     struct asy *ap = &Asy[dev];
  708.     struct iface *ifp = ap->iface;
  709.     int result;
  710.  
  711.     if ( ap->rlsd_line_control & IGNORED ) {
  712.         return IGNORED;
  713.     }
  714.  
  715.     switch ( new_rlsd ) {
  716.     case IGNORED:
  717.         /* Just return the current value */
  718.         return(ap->rlsd_line_control);
  719.  
  720.     case MOVED_DOWN:
  721.         if ( !(ap->rlsd_line_control & FOUND_UP) ) {
  722.             /* Already at requested value */
  723.             return(new_rlsd);
  724.         }
  725.         break;
  726.     case MOVED_UP:
  727.         if ( ap->rlsd_line_control & FOUND_UP ) {
  728.             /* Already at requested value */
  729.             return(new_rlsd);
  730.         }
  731.         break;
  732.     };
  733.  
  734.     /* Wait for state change to requested value */
  735.     while (ap->rlsd_line_control != new_rlsd) {
  736.         kpause(2L);
  737.         kwait( &(ap->rlsd_line_control) );
  738.     }
  739.  
  740.     if ( ap->rlsd_line_control & FOUND_UP )
  741.         result = PARAM_UP;
  742.     else /* DOWN or IGNORED */
  743.         result = PARAM_DOWN;
  744.  
  745.     /* set our control signals to follow RLSD */
  746.     if ( ifp->ioctl != NULL )
  747.         (*ifp->ioctl)( ifp, result, TRUE, 0L );
  748.     if ( ifp->iostatus != NULL )
  749.         (*ifp->iostatus)( ifp, result, 0L );
  750.     return(ap->rlsd_line_control);
  751. }
  752.  
  753.  
  754. /* Monitor RLSD signal, and report status changes */
  755. static void
  756. asy_monitor( dev, p1, p2 )
  757. int dev;
  758. void *p1;
  759. void *p2;
  760. {
  761.     int save_rlsd = Asy[dev].rlsd_line_control;
  762.  
  763.     while ( save_rlsd != IGNORED ) {
  764.         save_rlsd = get_rlsd_asy( dev,
  765.             ( save_rlsd ^ FOUND_UP ) | MOVED_DOWN );
  766.     }
  767.     Asy[dev].monitor = NULL;
  768. }
  769.  
  770.  
  771. /* Poll the asynch input queues; called on every clock tick.
  772.  * This helps limit the interrupt ring buffer occupancy when long
  773.  * packets are being received.
  774.  */
  775. void
  776. asytimer()
  777. {
  778. register struct asy *asyp;
  779. register struct fifo *fp;
  780. register int i;
  781.  
  782.     for(i=0;i<ASY_MAX;i++){
  783.         asyp = &Asy[i];
  784.         fp = &asyp->fifo;
  785.         if(fp->cnt != 0)
  786.             ksignal(fp,1);
  787.         if(asyp->dma.flags != 0 && (inportb(asyp->addr+LSR) & LSR_THRE) \
  788.                                 /* transmit interrupt should be on !,
  789.                                  * ie no flow control */
  790.                                 && (inportb(asyp->addr+IER) & IER_TxE) ){
  791.             asyp->txto++;
  792.             asytxint(asyp->iface->dev);
  793.         }
  794. #ifdef TIPMAIL
  795.         if (Tipsuspended[i].ifp)    {
  796.             if (!carrier_detect(i))    {
  797.                 char buf[40];
  798.                 sprintf (buf, "start tip %s %s %d\n", Tipsuspended[i].ifp->name, (Tipsuspended[i].modem) ? "m" : "t", Tipsuspended[i].timeout);
  799.                 cmdparse(Cmds,buf,NULL);
  800.                 Tipsuspended[i].ifp = 0;
  801.                 Tipsuspended[i].modem = 0;
  802.                 Tipsuspended[i].timeout = 0;
  803.             }
  804.         }
  805. #endif
  806.     }
  807. }
  808.  
  809.  
  810. int
  811. doasystat(argc,argv,p)
  812. int argc;
  813. char *argv[];
  814. void *p;
  815. {
  816.     register struct asy *asyp;
  817.  
  818.     for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
  819.         if(asyp->iface == NULLIF)
  820.             continue;
  821.  
  822.         tprintf("%s:",asyp->iface->name);
  823.         if(asyp->is_16550a)
  824.             tputs(" [NS16550A]");
  825.         if(asyp->trigchar != -1)
  826.             tprintf(" [trigger 0x%02x]",asyp->trigchar);
  827.         switch (asyp->cts_flow_control) {
  828.         case MOVED_DOWN:
  829.         case MOVED_UP:
  830.             tputs(" [cts flow control]");
  831.             break;
  832.         };
  833.         switch (asyp->rlsd_line_control) {
  834.         case MOVED_DOWN:
  835.         case MOVED_UP:
  836.             tputs(" [rlsd line control]");
  837.             break;
  838.         case IGNORED:
  839.             tputs(" [blind]");
  840.             break;
  841.         };
  842.         tprintf(" %lu bps\n",asyp->speed);
  843.  
  844.         tprintf(" RX: %lu int, %lu chr, %lu hw over, %lu hw hi,",
  845.             asyp->rxints,
  846.             asyp->rxchar,
  847.             asyp->overrun,
  848.             asyp->rxhiwat);
  849.         asyp->rxhiwat = 0;
  850.         if(asyp->is_16550a)
  851.             tprintf(" %lu fifo TO,",asyp->fifotimeouts);
  852.         tprintf(" %lu sw over, %u sw hi\n",
  853.             asyp->fifo.overrun,
  854.             asyp->fifo.hiwat);
  855.         asyp->fifo.hiwat = 0;
  856.  
  857.         if(tprintf(" TX: %lu int, %lu chr, %u q, %lu MS int, %lu THRE TO\n",
  858.             asyp->txints,
  859.             asyp->txchar,
  860.             len_q(asyp->sndq),
  861.             asyp->msint_count,
  862.             asyp->txto) == EOF)
  863.             break;
  864.     }
  865.     return 0;
  866. }
  867. /* Send a message on the specified serial line */
  868. int
  869. asy_send(dev,bp)
  870. int dev;
  871. struct mbuf *bp;
  872. {
  873.     if(dev < 0 || dev >= ASY_MAX)
  874.         return -1;
  875.     enqueue(&Asy[dev].sndq,bp);
  876.     return 0;
  877. }
  878.  
  879. /* Serial transmit process, common to all protocols */
  880. static void
  881. asy_tx(dev,p1,p2)
  882. int dev;
  883. void *p1;
  884. void *p2;
  885. {
  886.     register struct mbuf *bp;
  887.     struct asy *asyp;
  888.     struct dma *dp;
  889.     int i_state;
  890.  
  891.     asyp = &Asy[dev];
  892.     dp = &asyp->dma;
  893.  
  894.     for(;;){
  895.         /* Fetch a buffer for transmission */
  896.         while(asyp->sndq == NULLBUF)
  897.             kwait(&asyp->sndq);
  898.  
  899.         bp = dequeue(&asyp->sndq);
  900.  
  901.         while(bp != NULLBUF){
  902.             /* Start the transmitter */
  903.             asy_output(dev,bp->data,bp->cnt);
  904.  
  905.             /* Wait for completion */
  906.             i_state = disable ();
  907.             while(dp->flags == 1)
  908.                 kwait(asyp);
  909.             restore(i_state);
  910.  
  911.             /* Now do next buffer on chain */
  912.             bp = free_mbuf(bp);
  913.         }
  914.     }
  915. }
  916.  
  917. int
  918. carrier_detect(int dev)
  919. {
  920.     struct asy *ap = &Asy[dev];
  921.     unsigned base = ap->addr;
  922.  
  923.     ap->msr = inportb(base+MSR);
  924.     if ( ap->msr & MSR_RLSD ) {
  925.          return 1;
  926.     } else {
  927.          return 0;
  928.     }
  929. }
  930.  
  931.  
  932. #endif /* MSDOS */
  933.  
  934.